/**
 * Created by ${PRODUCT_NAME}.
 * User: skyler
 * Date: 2/14/11
 * Time: 9:42 AM
 * To change this template use File | Settings | File Templates.
 */
package com.thoughtorigin.media {
import com.thoughtorigin.application.Disposable;

import flash.events.EventDispatcher;
import flash.events.NetStatusEvent;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.utils.clearInterval;
import flash.utils.setInterval;

public class ProgressiveVideoPlayer extends EventDispatcher implements MediaPlayer {

    private var _video: Video;
    private var _url: String;
    private var _netStream: NetStream;
    private var _autoPlay: Boolean;
    private var _bufferTime: Number;
    private var _metaData: ProgressiveVideoMetaData;
    private var _loadingInterval: uint;
    private var _hasStarted: Boolean;
    private var _tickInterval: uint;
    private var _tickIntervalSet: Boolean;

    public function ProgressiveVideoPlayer(video: Video) {
        _video = video;
        _netStream = createNetStream();
        _netStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus, false, 0, true);
        _loadingInterval = setInterval(onInterval, 0);
    }

    private function onInterval(): void {
        if(_netStream.bytesLoaded < _netStream.bytesTotal) {
            dispatchEvent(new MediaPlayerEvent(MediaPlayerEvent.MEDIA_LOADING_EVENT, _netStream, _metaData));
        } else {
            clearInterval(_loadingInterval);
        }
    }

    private function onNetStatus(event:NetStatusEvent):void {
        switch(event.info.code) {
            case NetStatus.BUFFER_EMPTY:
                dispatchEvent(new MediaPlayerEvent(MediaPlayerEvent.BUFFER_EMPTY, _netStream, _metaData));
                clearTickInterval();
                break;
            case NetStatus.PLAY_STOP:
                if(time >= duration) {
                    dispatchEvent(new MediaPlayerEvent(MediaPlayerEvent.MEDIA_END, _netStream, _metaData));
                }
                clearTickInterval();
                break;
            case NetStatus.STREAM_NOT_FOUND:
                throw new MediaPlayerError("Video stream " + _url + " not found");
                break;
        }
    }

    private function clearTickInterval(): void {
        clearInterval(_tickInterval)
        _tickIntervalSet = false;
    }

    private function startTickInterval(): void {
        if(!_tickIntervalSet) {
            _tickInterval = setInterval(onMediaTick, 1000);
            _tickIntervalSet = true;
        }
    }

    public function onMetaData(meta : Object): void {
        _metaData = new ProgressiveVideoMetaData(meta);
    }

    public function set url(value:String):void {
        _url = value;
        if(_video && _netStream) {
            _netStream.play(url);
            _video.attachNetStream(_netStream);
            _hasStarted = false;
            if(!_autoPlay) {
                pause();
            } else {
                play();
            }
        }
    }

    public function get url():String {
        return _url;
    }

    public function play():void {
        _netStream.resume();
        if(time == 0 && !_hasStarted) {
            dispatchEvent(new MediaPlayerEvent(MediaPlayerEvent.MEDIA_START, _netStream, _metaData));
        }
        dispatchEvent(new MediaPlayerEvent(MediaPlayerEvent.MEDIA_PLAY, _netStream, _metaData));
        startTickInterval();
    }

    private function onMediaTick(): void {
        dispatchEvent(new MediaPlayerEvent(MediaPlayerEvent.MEDIA_TICK, _netStream, _metaData));
    }

    public function stop():void {
        _netStream.pause();
        _netStream.close();
        clearTickInterval();
        clearInterval(_loadingInterval);
        dispatchEvent(new MediaPlayerEvent(MediaPlayerEvent.MEDIA_CLOSE, _netStream, _metaData));
    }

    public function pause():void {
        _netStream.pause();
        clearTickInterval();
        dispatchEvent(new MediaPlayerEvent(MediaPlayerEvent.MEDIA_PAUSE, _netStream, _metaData));
    }

    public function resume():void {
        _netStream.resume();
        startTickInterval();
        dispatchEvent(new MediaPlayerEvent(MediaPlayerEvent.MEDIA_PLAY, _netStream, _metaData));
    }

    public function get duration():Number {
        return _metaData.duration;
    }

    public function get time():Number {
        return _netStream.time;
    }

    public function seek(value:Number):void {
        _netStream.seek(value);
        dispatchEvent(new MediaPlayerEvent(MediaPlayerEvent.MEDIA_SEEK, _netStream, _metaData));
    }

    public function set volume(value:Number): void {
        _netStream.soundTransform.volume = value;
        dispatchEvent(new VolumeEvent(VolumeEvent.VOLUME_CHANGE, value));
    }

    public function get volume():Number {
        return _netStream.soundTransform.volume;
    }

    protected function createNetStream(): NetStream {
        var retVal: NetStream = new NetStream(createNetConnection());
        retVal.client = this;
        return retVal;
    }

    protected function createNetConnection(): NetConnection {
        var retVal: NetConnection = new NetConnection();
        retVal.connect(null);
        return retVal;
    }

    public function dispose(... args):void {
        stop();
        _netStream.removeEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
        clearInterval(_loadingInterval);
        clearTickInterval();
        _video = null;
        _netStream = null;
    }

    public function get autoPlay():Boolean {
        return _autoPlay;
    }

    public function set autoPlay(value:Boolean):void {
        _autoPlay = value;
    }

    public function get bufferTime():Number {
        return _bufferTime;
    }

    public function set bufferTime(value:Number):void {
        _bufferTime = value;
    }

}
}
